package com.partsoft.dits.message;

import java.io.BufferedInputStream;
import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStream;
import java.io.StringWriter;
import java.io.UnsupportedEncodingException;
import java.text.DateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.Iterator;
import java.util.List;
import java.util.Map;


import org.codehaus.jackson.JsonNode;
import org.codehaus.jackson.map.ObjectMapper;
import org.dom4j.Attribute;
import org.dom4j.Document;
import org.dom4j.DocumentFactory;
import org.dom4j.Element;
import org.dom4j.Namespace;
import org.dom4j.Node;
import org.dom4j.io.OutputFormat;
import org.dom4j.io.SAXReader;
import org.dom4j.io.XMLWriter;
import org.springframework.core.io.ClassPathResource;
import org.springframework.util.Assert;
import org.springframework.util.StringUtils;
import org.xml.sax.EntityResolver;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;

import com.partsoft.dits.log.Log;
import com.partsoft.dits.utils.CalendarUtils;
import com.partsoft.dits.utils.Dom4jUtils;
import com.partsoft.dits.utils.MessageEntityUtils;
import com.partsoft.utils.CalendarUtils.DateFormatType;

@SuppressWarnings({ "unchecked" })
public class MessageProcessorImpl implements MessageProcessor {

	protected static final int MESSAGE_MIN_SIZE = 10;

	// XML消息处理部分
	static final String DITS_MESSAGE_XSD_CLASSPATH = "/com/surekam/dits/dits-message.xsd";

	static final String DITS_MESSAGE_NAMESPACE_URI = "http://inteldata.surekam.cn/dits/message";

	protected DateFormatType messageDateFormatType = DateFormatType.XML_DATETIMEFORMAT;

	protected DateFormat messageDateFormat = CalendarUtils.getDateFormat(getMessageDateFormatType());

	protected String messageNamespace = null;

	protected MessageFormat defaultMessageFormat = MessageFormat.XML;

	protected ObjectMapper jsonMapper = new ObjectMapper();

	{
		jsonMapper.setDateFormat(getMessageDateFormat());
	}

	public MessageProcessorImpl() {
	}

	public DateFormatType getMessageDateFormatType() {
		return messageDateFormatType;
	}

	public String getMessageNamespace() {
		return messageNamespace;
	}

	public MessageFormat getDefaultMessageFormat() {
		return defaultMessageFormat;
	}

	public void setDefaultMessageFormat(MessageFormat defaultMessageFormat) {
		this.defaultMessageFormat = defaultMessageFormat;
	}

	public void setMessageNamespace(String messageNamespace) {
		this.messageNamespace = messageNamespace;
	}

	public void setMessageDateFormatType(DateFormatType jsonDateFormat) {
		this.messageDateFormatType = jsonDateFormat;
		setMessageDateFormat(CalendarUtils.getDateFormat(this.messageDateFormatType));
	}

	// 智能判断消息格式实现
	public MessageEntity fromMessageBytes(InputStream messageInputStream) throws MessageException {
		Assert.notNull(messageInputStream);
		InputStream baism = messageInputStream;
		if (!baism.markSupported()) {
			baism = new BufferedInputStream(baism);
		}
		baism.mark(MESSAGE_MIN_SIZE * 20);
		byte[] typeBytes = new byte[MESSAGE_MIN_SIZE];
		boolean xmlType = true;
		try {
			Assert.isTrue(baism.read(typeBytes) == MESSAGE_MIN_SIZE, "消息字节码内容太少，不足以表示一个消息实体");
			xmlType = typeBytes[0] != '{';
		} catch (Exception e) {
			throw new MessageException(e.getMessage(), e);
		} finally {
			try {
				baism.reset();
			} catch (IOException e) {
				throw new MessageException(e.getMessage(), e);
			}
		}

		return xmlType ? fromXML(baism) : fromJSON(baism);

	}

	public MessageEntity fromMessageBytes(String messageString) throws MessageException {
		byte messageBytes[] = null;
		try {
			messageBytes = messageString.getBytes("utf-8");
		} catch (UnsupportedEncodingException e) {
			throw new IllegalArgumentException(e.getMessage(), e);
		}
		return fromMessageBytes(messageBytes);
	}

	public MessageEntity fromMessageBytes(byte[] messageBytes) throws MessageException {
		Assert.notNull(messageBytes);
		Assert.isTrue(messageBytes.length > 0);
		ByteArrayInputStream bis = new ByteArrayInputStream(messageBytes);
		return fromMessageBytes(bis);
	}

	public String toMessageBytes(MessageEntity msgEntity, MessageFormat format) {
		Assert.notNull(msgEntity);
		format = format == null ? getDefaultMessageFormat() : format;
		return format == MessageFormat.XML ? toXML(msgEntity) : toJSON(msgEntity);
	}

	public String toMessageBytes(MessageEntity msgEntity) {
		return toMessageBytes(msgEntity, getDefaultMessageFormat());
	}

	// XML格式部分
	// TODO 此处需要考虑速度优化
	protected SAXReader createXsdValidateReader() {
		ClassPathResource xsdResource = new ClassPathResource(resolveMessageXMLXSDClassPath(), this.getClass());
		InputStream xsdInputStream = null;
		try {
			xsdInputStream = xsdResource.getInputStream();
		} catch (IOException e) {
			return createNormalReader();
		}

		SAXReader reader = new SAXReader(true);
		reader.setEncoding("utf-8");
		try {
			reader.setEntityResolver(new MessageEntityResolver(xsdResource.getInputStream()));
			reader.setFeature("http://xml.org/sax/features/validation", true);
			reader.setFeature("http://apache.org/xml/features/validation/schema", true);
			reader.setFeature("http://xml.org/sax/features/namespace-prefixes", true);
			reader.setFeature("http://apache.org/xml/features/validation/schema-full-checking", true);
			reader.setProperty(
					"http://apache.org/xml/properties/schema/external-noNamespaceSchemaLocation",
					new StringBuilder(resolveMessageXMLDefaultNamespaceURI()).append(" ")
							.append(xsdResource.getURL().toString()).toString());
		} catch (Throwable e) {
			Log.fatal(String.format("打开消息XSD文件(%s)时出错。", resolveMessageXMLXSDClassPath()), e);
			throw new IllegalStateException(String.format("打开消息XSD文件(%s)时出错。", resolveMessageXMLXSDClassPath()), e);
		} finally {
			if (xsdInputStream != null) {
				try {
					xsdInputStream.close();
				} catch (IOException e) {
				}
			}
		}
		return reader;
	}

	protected String resolveMessageXMLXSDClassPath() {
		return DITS_MESSAGE_XSD_CLASSPATH;
	}

	protected SAXReader createNormalReader() {
		SAXReader reader = new SAXReader();
		reader.setEncoding("utf-8");
		return reader;
	}

	public MessageEntity fromXML(String xmlString) throws MessageException {
		byte[] xmlBytes;
		try {
			xmlBytes = xmlString.getBytes("utf-8");
			return fromXML(xmlBytes);
		} catch (UnsupportedEncodingException e) {
			throw new MessageException("字符串转成utf-8编码时出错");
		}
	}

	public MessageEntity fromXML(StringBuffer xmlBuffer) throws MessageException {
		return fromXML(xmlBuffer.toString());
	}

	public static String xPathAttachNameSpace(String xpath, String prefix) {
		if (!StringUtils.hasText(prefix))
			return xpath;
		String[] strs = xpath.split("/");
		StringBuffer tempPath = new StringBuffer();
		for (String str : strs) {
			if (".".equals(str) || "..".equals(str)) {
				tempPath.append(str);
			} else if (!"".equals(str)) {
				tempPath.append(prefix).append(":").append(str);
			}
			tempPath.append("/");
		}
		tempPath.deleteCharAt(tempPath.length() - 1);
		return tempPath.toString();
	}

	protected String resolveMessageIdNodeXPath() {
		return "./head/msgid";
	}

	protected String resolveMessageCodeNodeXPath() {
		return "./head/msgcode";
	}

	protected String resolveMessageDefaultActionNodeXPath() {
		return "./head/action";
	}

	protected String resolveMessageFromNodeXPath() {
		return "./head/sourcesystem";
	}

	protected String resolveMessageCreateTimeNodeXPath() {
		return "./head/ctime";
	}

	/**
	 * 读取消息头。
	 */
	protected void readMessageHeader(BaseMessageHeader header, Document doc, String prefix) {
		Assert.notNull(doc);
		Assert.isTrue(doc.getRootElement().getName().equals("dits"), "消息必须以<dits>节点开始。");
		Node msgIdNode = doc.getRootElement().selectSingleNode(
				xPathAttachNameSpace(resolveMessageIdNodeXPath(), prefix));
		// Assert.notNull(msgIdNode, "找不到<msgid>节点。");
		Node msgCodeNode = doc.getRootElement().selectSingleNode(
				xPathAttachNameSpace(resolveMessageCodeNodeXPath(), prefix));
		Assert.notNull(msgCodeNode, "找不到<msgcode>节点。");
		Node msgActionNode = doc.getRootElement().selectSingleNode(
				xPathAttachNameSpace(resolveMessageDefaultActionNodeXPath(), prefix));
		Assert.notNull(msgActionNode, "找不到<action>节点。");
		Node msgSourceSystemNode = doc.getRootElement().selectSingleNode(
				xPathAttachNameSpace(resolveMessageFromNodeXPath(), prefix));
		// Assert.notNull(msgSourceSystemNode, "找不到<sourcesystem>节点。");
		Node msgCtimeNode = doc.getRootElement().selectSingleNode(
				xPathAttachNameSpace(resolveMessageCreateTimeNodeXPath(), prefix));
		// Assert.notNull(msgCtimeNode, "找不到<ctime>节点。");

		String standardTableName = msgCodeNode.getStringValue();
		Assert.hasText(standardTableName, "<msgcode>未指定内容");
		DataAction msgAction = DataAction.fromName(msgActionNode.getStringValue());
		Assert.notNull(msgAction, "<action>节点内容不正确");
		Date ctm = new Date();
		if (msgCtimeNode != null)
			try {
				ctm = getMessageDateFormat().parse(msgCtimeNode.getStringValue());
			} catch (Exception e) {
			}

		header.setMessageCode(Dom4jUtils.decodeXML(standardTableName));
		header.setMessageId(msgIdNode == null || !StringUtils.hasText(msgIdNode.getStringValue()) ? new StringBuilder(
				standardTableName).append(CalendarUtils.idDateTimeFormat.format(ctm)).toString() : Dom4jUtils
				.decodeXML(msgIdNode.getStringValue()));
		header.setDefaultAction(msgAction);
		header.setFrom(msgSourceSystemNode == null || !StringUtils.hasText(msgSourceSystemNode.getStringValue()) ? getMessageNamespace()
				: Dom4jUtils.decodeXML(msgSourceSystemNode.getStringValue()));
		header.setCreateTime(ctm);
	}

	protected String resolveMessageDataPropertyNodeXPath() {
		return "./field";
	}

	protected String resolveMessageDataPropertyValueNodeXPath() {
		return "./value";
	}

	protected String resolveMessageDataPropertyValueAttributeName() {
		return "value";
	}

	protected String resolveMessageDataPropertyTypeAttributeName() {
		return "type";
	}

	protected String resolveMessageDataPropertyFormatAttributeName() {
		return "format";
	}

	/**
	 * 读取字段内容
	 */
	protected void readFeildsFromRowElement(BaseMessageDataItem rowItem, Node rowNode, String prefix) {
		Assert.notNull(rowNode);
		Assert.notNull(rowItem);
		List<Node> fieldNodes = rowNode
				.selectNodes(xPathAttachNameSpace(resolveMessageDataPropertyNodeXPath(), prefix));
		for (Node fieldNode : fieldNodes) {
			if (!(fieldNode instanceof Element))
				continue;
			Element fnEl = (Element) fieldNode;
			Assert.notNull(fnEl.attribute(resolveMessageDataPropertyAttributeName()),
					String.format("节点(%s)必须有%s属性", fnEl.getPath(), resolveMessageDataPropertyAttributeName()));
			String columnName = fnEl.attributeValue(resolveMessageDataPropertyAttributeName());
			columnName = Dom4jUtils.decodeXML(columnName);
			String colValue = null;
			Integer columnType = null;
			// String format = null;

			Node valueNode = fnEl.selectSingleNode(xPathAttachNameSpace(resolveMessageDataPropertyValueNodeXPath(),
					prefix));
			if (valueNode != null) {
				colValue = valueNode.getStringValue();
			} else {
				Attribute valueAttr = fnEl.attribute(resolveMessageDataPropertyValueAttributeName());
				if (valueAttr != null)
					colValue = fnEl.attributeValue(resolveMessageDataPropertyValueAttributeName());
			}
			if (fnEl.attribute(resolveMessageDataPropertyTypeAttributeName()) != null) {
				try {
					columnType = new Integer(fnEl.attributeValue(resolveMessageDataPropertyTypeAttributeName()));
				} catch (Throwable e) {
				}
			}

			colValue = Dom4jUtils.decodeXML(colValue);

			// 暂不实现格式
			// if
			// (fnEl.attribute(resolveMessageDataPropertyFormatAttributeName())
			// != null) {
			// format =
			// fnEl.attributeValue(resolveMessageDataPropertyFormatAttributeName());
			// }
			rowItem.putValue(new DataProperty(columnName, columnType), colValue);
		}
	}

	/**
	 * 获得数据节点的XPATH
	 * 
	 * @return
	 */
	protected String resolveMessageDataNodeXPath() {
		return "./row";
	}

	protected String resolveMessageDataActionAttributeName() {
		return "action";
	}

	protected String resolveMessageDataPropertyAttributeName() {
		return "name";
	}

	/**
	 * 从rows节点中读取所有<row>节点至数据中。
	 * 
	 * @param msgEntity
	 * @param rowsNode
	 * @param prefix
	 */
	protected void readDataMessageFromRowsElement(BaseMessageEntity msgEntity, Node rowsNode, String prefix) {
		Assert.notNull(msgEntity);
		Assert.notNull(rowsNode);
		List<Node> rowNods = rowsNode.selectNodes(xPathAttachNameSpace(resolveMessageDataNodeXPath(), prefix));
		for (Node rowNode : rowNods) {
			if (!(rowNode instanceof Element))
				continue;
			Element rwEl = (Element) rowNode;
			BaseMessageDataItem rowItem = new BaseMessageDataItem(msgEntity);
			DataAction rowAction = rwEl.attribute(resolveMessageDataActionAttributeName()) != null ? DataAction
					.fromName(rwEl.attributeValue(resolveMessageDataActionAttributeName())) : rowItem.getOwner()
					.getHeader().getDefaultAction();
			rowAction = rowAction == null ? msgEntity.getHeader().getDefaultAction() : rowAction;
			rowItem.setAction(rowAction);
			// 分析所有字段
			readFeildsFromRowElement(rowItem, rowNode, prefix);
			if (rowItem.getValues().size() == 0)
				continue;
			// 分析关联
			readDataRelationFromRowElement(rowItem, rowNode, prefix);

			msgEntity.addData(rowItem);
		}
	}

	/**
	 * 读取消息实体数据
	 */
	protected void readDataMessageDatas(BaseMessageEntity msgEntity, Document doc, String prefix) {
		Assert.notNull(msgEntity);
		Assert.notNull(doc);
		Node rootRowsNode = doc.getRootElement().selectSingleNode(
				xPathAttachNameSpace(resolveMessageDatasNodeXPath(), prefix));
		if (rootRowsNode != null) {
			readDataMessageFromRowsElement(msgEntity, rootRowsNode, prefix);
		}
	}

	/**
	 * 获得数据列表节点的XPATH
	 * 
	 * @return
	 */
	protected String resolveMessageDatasNodeXPath() {
		return "./rows";
	}

	/**
	 * 获得上级关联的消息节点XPATH
	 * 
	 * @return
	 */
	protected String resolveMessageDataRelationParentNodeXPath() {
		return "./relation/parents/parent";
	}

	protected String resolveMessageDataRelationChildNodeXPath() {
		return "./relation/childs/child";
	}

	/**
	 * 从row节点中读取关联数据
	 */
	protected void readDataRelationFromRowElement(BaseMessageDataItem rowItem, Node rowNode, String prefix) {
		Assert.notNull(rowNode);
		Assert.notNull(rowItem);
		List<Node> parentNodes = rowNode.selectNodes(xPathAttachNameSpace(resolveMessageDataRelationParentNodeXPath(),
				prefix));
		int msgRelationId = 1;
		for (Node parentNode : parentNodes) {
			if (!(parentNode instanceof Element))
				continue;
			Element pl = (Element) parentNode;
			Assert.notNull(pl.attribute(resolveMessageDataPropertyAttributeName()),
					String.format("节点(%s)必须包含%s属性。", pl.getPath(), resolveMessageDataPropertyAttributeName()));
			String newMessageCode = pl.attributeValue(resolveMessageDataPropertyAttributeName());
			Assert.hasText(newMessageCode, String.format("节点(%s)的name属性必须包含内容。", pl.getPath()));
			newMessageCode = Dom4jUtils.decodeXML(newMessageCode);
			DataAction rowAction = pl.attribute(resolveMessageDataActionAttributeName()) != null ? DataAction
					.fromName(pl.attributeValue(resolveMessageDataActionAttributeName())) : rowItem.getAction();
			rowAction = rowAction == null ? rowItem.getAction() : rowAction;

			BaseMessageEntity parentEntity = new BaseMessageEntity();
			parentEntity.setOwner(rowItem.getOwner());
			BaseMessageHeader newHeader = new BaseMessageHeader(rowItem.getOwner().getHeader());
			newHeader.setMessageId(newHeader.getMessageId() + (rowItem.getOwner().isTop() ? ".p." : ".")
					+ msgRelationId++);
			newHeader.setMessageCode(newMessageCode);
			newHeader.setDefaultAction(rowAction);

			parentEntity.setHeader(newHeader);
			BaseMessageDataItem parentRowItem = new BaseMessageDataItem(parentEntity);
			readFeildsFromRowElement(parentRowItem, parentNode, prefix);
			readDataRelationFromRowElement(parentRowItem, parentNode, prefix);
			parentEntity.addData(parentRowItem);
			rowItem.addParent(parentEntity);
		}

		List<Node> childNodes = rowNode.selectNodes(xPathAttachNameSpace(resolveMessageDataRelationChildNodeXPath(),
				prefix));
		msgRelationId = 1;
		for (Node childNode : childNodes) {
			if (!(childNode instanceof Element))
				continue;
			Element cl = (Element) childNode;
			Assert.notNull(cl.attribute(resolveMessageDataPropertyAttributeName()),
					String.format("节点(%s)必须包含%s属性。", cl.getPath(), resolveMessageDataPropertyAttributeName()));
			String newMessageCode = cl.attributeValue(resolveMessageDataPropertyAttributeName());
			Assert.hasText(newMessageCode,
					String.format("节点(%s)的%s属性必须包含内容。", cl.getPath(), resolveMessageDataPropertyAttributeName()));
			newMessageCode = Dom4jUtils.decodeXML(newMessageCode);
			DataAction rowAction = cl.attribute(resolveMessageDataActionAttributeName()) != null ? DataAction
					.fromName(cl.attributeValue(resolveMessageDataActionAttributeName())) : rowItem.getAction();
			rowAction = rowAction == null ? rowItem.getAction() : rowAction;

			BaseMessageEntity childEntity = new BaseMessageEntity();
			childEntity.setOwner(rowItem.getOwner());
			BaseMessageHeader newHeader = new BaseMessageHeader(rowItem.getOwner().getHeader());
			newHeader.setMessageId(newHeader.getMessageId() + (rowItem.getOwner().isTop() ? ".c." : ".")
					+ msgRelationId++);
			newHeader.setMessageCode(newMessageCode);
			newHeader.setDefaultAction(rowAction);
			childEntity.setHeader(newHeader);
			Node clRowsNode = cl.selectSingleNode(xPathAttachNameSpace(resolveMessageDatasNodeXPath(), prefix));
			if (clRowsNode != null) {
				readDataMessageFromRowsElement(childEntity, clRowsNode, prefix);
			}
			rowItem.addChild(childEntity);
		}

	}

	protected String resolveMessageDefaultXMLNamespacePrefix() {
		return "dits";
	}

	public MessageEntity fromXML(byte[] xmlBytes) throws MessageException {
		Assert.notNull(xmlBytes);
		Assert.isTrue(xmlBytes.length > 0);
		return fromXML(new ByteArrayInputStream(xmlBytes));
	}

	public MessageEntity fromXML(InputStream xmlStream) throws MessageException {
		Assert.notNull(xmlStream);
		InputStream baism = xmlStream;
		if (!baism.markSupported()) {
			baism = new BufferedInputStream(baism);
		}
		// TODO 缓存数据太小，可能存在问题？！！， 是否需要把当前文件写入临时文件中，然后再读取？？
		baism.mark(8192);
		try {
			Document doc = null;
			String prefixName = resolveMessageDefaultXMLNamespacePrefix();
			try {
				doc = createXsdValidateReader().read(baism);
				Namespace dNs = doc.getRootElement().getNamespaceForURI(resolveMessageXMLDefaultNamespaceURI());
				if (dNs == null) {
					doc.getRootElement().addNamespace(prefixName, resolveMessageXMLDefaultNamespaceURI());
				} else {
					if (dNs.getPrefix().length() > 0) {
						prefixName = dNs.getPrefix();
					} else {
						doc.getRootElement().addNamespace(prefixName, resolveMessageXMLDefaultNamespaceURI());
					}
				}
			} catch (Throwable e) {
				baism.reset();
				doc = createNormalReader().read(baism);
				if (!StringUtils.hasText(doc.getRootElement().getNamespaceURI())) {
					prefixName = "";
				} else {
					doc.getRootElement().addNamespace(prefixName, doc.getRootElement().getNamespaceURI());
				}
			}

			BaseMessageHeader header = new BaseMessageHeader();
			readMessageHeader(header, doc, prefixName);
			BaseMessageEntity bmet = new BaseMessageEntity();
			bmet.setHeader(header);
			readDataMessageDatas(bmet, doc, prefixName);
			return bmet;
		} catch (Throwable e) {
			throw new MessageException(e.getMessage(), e);
		}
	}

	public static Element NCL(DocumentFactory docFactory, Element p, String name, String uri) {
		Assert.notNull(docFactory);
		Assert.notNull(p);
		Assert.hasText(name);
		name = Dom4jUtils.encodeXML(name);
		Element nel = docFactory.createElement(name, uri);
		p.add(nel);
		return nel;
	}

	public static Element NCLV(DocumentFactory docFactory, Element p, String name, String value, String uri) {
		Element cl = NCL(docFactory, p, name, uri);
		value = Dom4jUtils.encodeXML(value);
		cl.setText(value);
		return cl;
	}

	public static Attribute NATV(DocumentFactory docFactory, Element p, String name, String value) {
		Assert.notNull(docFactory);
		Assert.notNull(p);
		Assert.hasText(name);
		name = Dom4jUtils.encodeXML(name);
		value = Dom4jUtils.encodeXML(value);
		Attribute attr = docFactory.createAttribute(p, name, value);
		p.add(attr);
		return attr;
	}

	protected String resolveMessageHeadNodeName() {
		return "head";
	}

	protected String resolveMessageIdNodeName() {
		return "msgid";
	}

	protected String resolveMessageCodeNodeName() {
		return "msgcode";
	}

	protected String resolveMessageDefaultActionNodeName() {
		return "action";
	}

	protected String resolveMessageFromNodeName() {
		return "sourcesystem";
	}

	protected String resolveMessageCreateTimeNodeName() {
		return "ctime";
	}

	/**
	 * 写入消息头
	 */
	protected void writeToHeader(DocumentFactory docFactory, Element drtEl, MessageHeader header) {
		Assert.notNull(docFactory);
		Assert.notNull(drtEl);
		Assert.notNull(header);
		Element headEl = NCL(docFactory, drtEl, resolveMessageHeadNodeName(), resolveMessageXMLDefaultNamespaceURI());
		NCLV(docFactory, headEl, resolveMessageIdNodeName(), header.getMessageId(),
				resolveMessageXMLDefaultNamespaceURI());
		NCLV(docFactory, headEl, resolveMessageCodeNodeName(), header.getMessageCode(),
				resolveMessageXMLDefaultNamespaceURI());
		NCLV(docFactory, headEl, resolveMessageDefaultActionNodeName(), header.getDefaultAction().name(),
				resolveMessageXMLDefaultNamespaceURI());
		if (StringUtils.hasText(header.getFrom()))
			NCLV(docFactory, headEl, resolveMessageFromNodeName(), header.getFrom(),
					resolveMessageXMLDefaultNamespaceURI());
		NCLV(docFactory, headEl, resolveMessageCreateTimeNodeName(),
				CalendarUtils.toXmlDateTime(header.getCreateTime()), resolveMessageXMLDefaultNamespaceURI());
	}

	protected String resolveMessageDataPropertyNodeName() {
		return "field";
	}

	protected void writeMessageDataItemFields(DocumentFactory docFactory, Element drtEl, Map<DataProperty, String> datas) {
		Assert.notNull(docFactory);
		Assert.notNull(drtEl);
		for (Map.Entry<DataProperty, String> fEntry : datas.entrySet()) {
			Element cl = NCL(docFactory, drtEl, resolveMessageDataPropertyNodeName(),
					resolveMessageXMLDefaultNamespaceURI());
			NATV(docFactory, cl, resolveMessageDataPropertyAttributeName(), fEntry.getKey().getPropertyName());
			if (fEntry.getValue() != null)
				NATV(docFactory, cl, resolveMessageDataPropertyValueAttributeName(), fEntry.getValue());
			if (fEntry.getKey().getValueType() != null)
				NATV(docFactory, cl, resolveMessageDataPropertyTypeAttributeName(), fEntry.getKey().getValueType()
						.toString());
		}
	}

	protected String resolveMessageDataRelationNodeName() {
		return "relation";
	}

	protected String resolveMessageDataParentsNodeName() {
		return "parents";
	}

	protected String resolveMessageDataParentNodeName() {
		return "parent";
	}

	protected String resolveMessageDataChildsNodeName() {
		return "childs";
	}

	protected String resolveMessageDataChildNodeName() {
		return "child";
	}

	/**
	 * 写入行消息内容
	 */
	protected void writeMessageDataRelation(DocumentFactory docFactory, Element drtEl, MessageDataItem dItem) {
		Assert.notNull(docFactory);
		Assert.notNull(drtEl);
		Assert.notNull(dItem);

		Element rel = null;
		MessageEntity[] parents = dItem.getParents();
		MessageEntity[] childs = dItem.getChilds();
		if (parents.length > 0 || childs.length > 0)
			rel = NCL(docFactory, drtEl, resolveMessageDataRelationNodeName(), resolveMessageXMLDefaultNamespaceURI());
		if (rel != null) {
			if (parents.length > 0) {
				Element pls = NCL(docFactory, rel, resolveMessageDataParentsNodeName(),
						resolveMessageXMLDefaultNamespaceURI());
				for (MessageEntity parent : parents) {
					if (parent.getDatas().length == 0)
						continue;
					Assert.isTrue(parent.getDatas().length == 1, String.format("父级节点数据不能超过1条(%s)", parent.toString()));
					// 写入parent节点
					Element pl = NCL(docFactory, pls, resolveMessageDataParentNodeName(),
							resolveMessageXMLDefaultNamespaceURI());
					NATV(docFactory, pl, resolveMessageDataPropertyAttributeName(), parent.getHeader().getMessageCode());
					if (parent.getHeader().getDefaultAction() != parent.getOwner().getHeader().getDefaultAction())
						NATV(docFactory, pl, resolveMessageDataActionAttributeName(), parent.getHeader()
								.getDefaultAction().name());
					// 写入字段
					writeMessageDataItemFields(docFactory, pl, parent.getDatas()[0].getValues());
					// 再写上级的关联
					writeMessageDataRelation(docFactory, pl, parent.getDatas()[0]);
				}
			}

			if (childs.length > 0) {
				Element cls = NCL(docFactory, rel, resolveMessageDataChildsNodeName(),
						resolveMessageXMLDefaultNamespaceURI());
				for (MessageEntity child : childs) {
					if (child.getDatas().length == 0)
						continue;
					// 写入child节点
					Element cl = NCL(docFactory, cls, resolveMessageDataChildNodeName(),
							resolveMessageXMLDefaultNamespaceURI());
					NATV(docFactory, cl, resolveMessageDataPropertyAttributeName(), child.getHeader().getMessageCode());
					if (child.getHeader().getDefaultAction() != child.getOwner().getHeader().getDefaultAction())
						NATV(docFactory, cl, resolveMessageDataActionAttributeName(), child.getHeader()
								.getDefaultAction().name());
					// 写入字段
					writeMessageDatas(docFactory,
							NCL(docFactory, cl, resolveMessageDatasNodeName(), resolveMessageXMLDefaultNamespaceURI()),
							child.getDatas());
				}
			}
		}
	}

	protected String resolveMessageDataNodeName() {
		return "row";
	}

	/**
	 * 写入消息数据行
	 */
	protected void writeMessageDatas(DocumentFactory docFactory, Element drtEl, MessageDataItem[] datas) {
		Assert.notNull(docFactory);
		Assert.notNull(drtEl);
		Assert.notNull(datas);
		for (MessageDataItem dItem : datas) {
			Element dEl = NCL(docFactory, drtEl, resolveMessageDataNodeName(), resolveMessageXMLDefaultNamespaceURI());
			if (dItem.getAction() != dItem.getOwner().getHeader().getDefaultAction())
				NATV(docFactory, dEl, resolveMessageDataActionAttributeName(), dItem.getAction().name());
			writeMessageDataItemFields(docFactory, dEl, dItem.getValues());
			writeMessageDataRelation(docFactory, dEl, dItem);
		}
	}

	protected String resolveMessageXMLDefaultRootNodeName() {
		return "dits";
	}

	protected String resolveMessageXMLDefaultNamespaceURI() {
		return DITS_MESSAGE_NAMESPACE_URI;
	}

	public Document toDocument(MessageEntity entity) {
		DocumentFactory docFactory = createXsdValidateReader().getDocumentFactory();
		Document doc = docFactory.createDocument("utf-8");

		Element drtEl = docFactory.createElement(resolveMessageXMLDefaultRootNodeName(),
				resolveMessageXMLDefaultNamespaceURI());
		drtEl.addNamespace("xsi", "http://www.w3.org/2001/XMLSchema-instance");
		drtEl.addNamespace("schemaLocation", resolveMessageXMLDefaultNamespaceURI());
		doc.setRootElement(drtEl);
		writeToHeader(docFactory, drtEl, entity.getHeader());
		writeMessageDatas(docFactory,
				NCL(docFactory, drtEl, resolveMessageDatasNodeName(), resolveMessageXMLDefaultNamespaceURI()),
				entity.getDatas());
		return doc;
	}

	protected String resolveMessageDatasNodeName() {
		return "rows";
	}

	public String toXML(MessageEntity entity) {
		return toXMLString(entity).toString();
	}

	public StringBuffer toXMLString(MessageEntity entity) {
		Assert.notNull(entity);
		Document doc = toDocument(entity);
		StringWriter swr = new StringWriter();
		OutputFormat format = OutputFormat.createPrettyPrint();
		format.setEncoding("utf-8");
		format.setTrimText(true);
		format.setIndentSize(1);
		XMLWriter xmlWriter = null;
		try {
			xmlWriter = new XMLWriter(swr, format);
			xmlWriter.write(doc);
		} catch (Throwable e) {
			throw new IllegalStateException(String.format("输出XML时出现错误:%s", e.getMessage()), e);
		} finally {
			if (xmlWriter != null)
				try {
					xmlWriter.close();
				} catch (IOException e) {
				}
		}
		return swr.getBuffer();
	}

	public void saveXMLFile(MessageEntity entity, File file) throws IOException {
		Assert.notNull(entity);
		Assert.notNull(file);
		Document doc = toDocument(entity);
		OutputFormat format = OutputFormat.createPrettyPrint();
		format.setEncoding("utf-8");
		format.setIndent(true);
		FileWriter writer = null;
		XMLWriter xmlWriter = null;
		try {
			writer = new FileWriter(file);
			xmlWriter = new XMLWriter(writer, format);
			xmlWriter.write(doc);
			writer.close();
			xmlWriter.close();
		} catch (IOException e) {
			throw e;
		} finally {
			if (writer != null)
				try {
					writer.close();
				} catch (IOException e) {
				}
			if (xmlWriter != null)
				try {
					xmlWriter.close();
				} catch (IOException e) {
				}
		}
	}

	public DateFormat getMessageDateFormat() {
		return messageDateFormat;
	}

	public void setMessageDateFormat(DateFormat jsonDateFormat) {
		if (jsonDateFormat == null) {
			this.messageDateFormat = CalendarUtils.getDateFormat(getMessageDateFormatType());
		} else {
			this.messageDateFormat = jsonDateFormat;
		}
	}

	// JSON部分实现
	public MessageEntity fromJSON(byte[] jsonBytes) throws MessageException {
		Assert.notNull(jsonBytes);
		Assert.isTrue(jsonBytes.length > 0);
		ByteArrayInputStream bais = new ByteArrayInputStream(jsonBytes);
		return fromJSON(bais);
	}

	public MessageEntity fromJSON(InputStream jsonBytes) throws MessageException {
		Assert.notNull(jsonBytes);
		try {
			JsonNode jsonNode = jsonMapper.readValue(jsonBytes, JsonNode.class);
			JsonNode headerNode = jsonNode;
			Assert.notNull(headerNode, "不存在头信息节点");
			JsonNode messageCodeNode = headerNode.get("c");
			Assert.notNull(messageCodeNode, "不存在消息代码节点");
			String messageCode = messageCodeNode.getTextValue();
			Assert.hasText(messageCode, "不存在消息代码内容");

			JsonNode actionNode = headerNode.get("t");
			DataAction defaultAction = actionNode != null ? DataAction.fromCode(actionNode.getIntValue()) : null;
			Assert.notNull(defaultAction, "未指定消息缺省动作");

			JsonNode fromNode = headerNode.get("f");
			String from = fromNode == null || !StringUtils.hasText(fromNode.getTextValue()) ? getMessageNamespace()
					: fromNode.getTextValue();
			JsonNode messageIdNode = headerNode.get("k");
			JsonNode createTimeNode = headerNode.get("m");
			Date createTime = new Date();
			if (createTimeNode != null)
				try {
					createTime = getMessageDateFormat().parse(createTimeNode.getTextValue());
				} catch (Exception e) {
				}
			String messageId = messageIdNode == null || !StringUtils.hasText(messageIdNode.getTextValue()) ? new StringBuilder(
					messageCode).append(CalendarUtils.idDateTimeFormat.format(createTime)).toString() : messageIdNode
					.getTextValue();

			BaseMessageHeader messageHeader = new BaseMessageHeader();
			messageHeader.setMessageCode(messageCode);
			messageHeader.setMessageId(messageId);
			messageHeader.setCreateTime(createTime);
			messageHeader.setDefaultAction(defaultAction);
			messageHeader.setFrom(from);

			BaseMessageEntity msgEntity = new BaseMessageEntity();
			msgEntity.setHeader(messageHeader);
			readDataMessageDatas(msgEntity, jsonNode);
			return msgEntity;
		} catch (Throwable e) {
			throw new MessageException(e);
		}
	}

	protected void readDataMessageDatas(BaseMessageEntity msgEntity, JsonNode jsonNode) {
		Assert.notNull(msgEntity);
		Assert.notNull(jsonNode);
		JsonNode rowsNode = jsonNode.get("s");
		if (rowsNode != null && rowsNode.isArray()) {
			readDataMessageFromRowsElement(msgEntity, rowsNode);
		}
	}

	protected void readDataMessageFromRowsElement(BaseMessageEntity msgEntity, JsonNode rowsNode) {
		Iterator<JsonNode> nodeIter = rowsNode.iterator();
		int i = 0;
		while (nodeIter.hasNext()) {
			JsonNode itemNode = nodeIter.next();
			BaseMessageDataItem rowItem = new BaseMessageDataItem(msgEntity);
			JsonNode actionNode = itemNode.get("t");
			DataAction dataAction = actionNode != null ? DataAction.fromCode(actionNode.asInt()) : msgEntity
					.getHeader().getDefaultAction();
			rowItem.setAction(dataAction);
			JsonNode fieldsNode = itemNode.get("v");
			if (fieldsNode != null) {
				readFeildsFromRowElement(rowItem, fieldsNode);
				if (rowItem.hasValues()) {
					readDataRelationFromRowElement(rowItem, itemNode, i);
					msgEntity.addData(rowItem);
				}
			}
			i = i + 1;
		}
	}

	protected void readDataRelationFromRowElement(BaseMessageDataItem rowItem, JsonNode itemNode, int i) {
		JsonNode parentsNode = itemNode.get("p");
		if (parentsNode == null)
			return;
		Iterator<JsonNode> parentIter = parentsNode.iterator();
		int msgRelationId = 1;
		while (parentIter.hasNext()) {
			JsonNode parentNode = parentIter.next();
			JsonNode parentMessageCodeNode = parentNode.get("c");
			Assert.notNull(parentMessageCodeNode, String.format("消息(%s)数据，第%d条记录的第%d个父消息消息代码节点", rowItem.getOwner()
					.getHeader().getMessageId(), i + 1, msgRelationId));
			String parentMessageCode = parentMessageCodeNode.asText();
			Assert.hasText(parentMessageCode, String.format("消息(%s)数据，第%d条记录的第%d个父消息消息代码内容", rowItem.getOwner()
					.getHeader().getMessageId(), i + 1, msgRelationId));

			JsonNode actionNode = parentNode.get("t");
			DataAction rowAction = actionNode != null ? DataAction.fromCode(actionNode.asInt()) : rowItem.getAction();
			rowAction = rowAction == null ? rowItem.getAction() : rowAction;

			BaseMessageHeader parentMsgHeader = new BaseMessageHeader(rowItem.getOwner().getHeader());
			parentMsgHeader.setMessageCode(parentMessageCode);
			parentMsgHeader.setMessageId(parentMsgHeader.getMessageId() + (rowItem.getOwner().isTop() ? ".p." : ".")
					+ msgRelationId);
			BaseMessageEntity parentMsgEntity = new BaseMessageEntity();
			parentMsgEntity.setOwner(rowItem.getOwner());
			parentMsgEntity.setHeader(parentMsgHeader);
			JsonNode parentFieldsNode = parentNode.get("v");
			BaseMessageDataItem dataItem = new BaseMessageDataItem(parentMsgEntity);
			dataItem.setAction(rowAction);
			if (parentFieldsNode != null) {
				readFeildsFromRowElement(dataItem, parentFieldsNode);
			}
			readDataRelationFromRowElement(dataItem, parentFieldsNode, msgRelationId);
			if (dataItem.hasValues()) {
				parentMsgEntity.addData(dataItem);
				rowItem.addParent(parentMsgEntity);
				msgRelationId++;
			}
		}

		msgRelationId = 1;
		JsonNode childsNode = itemNode.get("l");
		Iterator<JsonNode> childIter = childsNode.iterator();
		while (childIter.hasNext()) {
			JsonNode childNode = childIter.next();
			JsonNode childMessageCodeNode = childNode.get("c");

			Assert.notNull(childMessageCodeNode, String.format("消息(%s)数据，第%d条记录的第%d个子消息无消息代码节点", rowItem.getOwner()
					.getHeader().getMessageId(), i + 1, msgRelationId));
			String childMessageCode = childMessageCodeNode.asText();
			Assert.hasText(childMessageCode, String.format("消息(%s)数据，第%d条记录的第%d个子消息无消息代码内容", rowItem.getOwner()
					.getHeader().getMessageId(), i + 1, msgRelationId));

			JsonNode actionNode = childNode.get("t");
			DataAction rowAction = actionNode != null ? DataAction.fromCode(actionNode.asInt()) : rowItem.getAction();
			rowAction = rowAction == null ? rowItem.getAction() : rowAction;

			BaseMessageEntity childEntity = new BaseMessageEntity();
			childEntity.setOwner(rowItem.getOwner());
			BaseMessageHeader newHeader = new BaseMessageHeader(rowItem.getOwner().getHeader());
			newHeader.setMessageId(newHeader.getMessageId() + (rowItem.getOwner().isTop() ? ".c." : ".")
					+ msgRelationId++);
			newHeader.setMessageCode(childMessageCode);
			newHeader.setDefaultAction(rowAction);
			childEntity.setHeader(newHeader);
			readDataMessageDatas(childEntity, childNode);
			if (childEntity.hasData()) {
				rowItem.addChild(childEntity);
			}
		}

	}

	protected void readFeildsFromRowElement(BaseMessageDataItem rowItem, JsonNode fieldsNode) {
		Iterator<Map.Entry<String, JsonNode>> fieldIter = fieldsNode.getFields();
		while (fieldIter.hasNext()) {
			Map.Entry<String, JsonNode> fieldMapEntry = fieldIter.next();
			JsonNode fieldNode = fieldMapEntry.getValue();
			String fieldName = fieldMapEntry.getKey();
			rowItem.putValue(fieldName, fieldNode.asText());
		}
	}

	public MessageEntity fromJSON(String jsonContent) throws MessageException {
		Assert.hasText(jsonContent);
		byte[] jsonBytes = null;
		try {
			jsonBytes = jsonContent.getBytes("utf-8");
		} catch (Exception e) {
			throw new MessageException("不能转成UTF8编码");
		}
		return fromJSON(new ByteArrayInputStream(jsonBytes));
	}

	public MessageEntity fromJSON(StringBuffer jsonContent) throws MessageException {
		Assert.notNull(jsonContent);
		return fromJSON(jsonContent.toString());
	}

	protected String escapeJSONText(String jsonText) {
		if (jsonText.indexOf("'") != -1) {
			// 将单引号转义一下，因为JSON串中的字符串类型可以单引号引起来的
			jsonText = jsonText.replaceAll("'", "\\\'");
		}
		if (jsonText.indexOf("\"") != -1) {
			// 将双引号转义一下，因为JSON串中的字符串类型可以单引号引起来的
			jsonText = jsonText.replaceAll("\"", "\\\\\"");
		}

		if (jsonText.indexOf("\r\n") != -1) {
			// 将回车换行转换一下，因为JSON串中字符串不能出现显式的回车换行
			jsonText = jsonText.replaceAll("\r\n", "\\\\u000d\\\\u000a");
		}
		if (jsonText.indexOf("\r") != -1) {
			// 将回车转换一下，因为JSON串中字符串不能出现显式的回车换行
			jsonText = jsonText.replaceAll("\r", "\\\\u000a");
		}
		if (jsonText.indexOf("\n") != -1) {
			// 将换行转换一下，因为JSON串中字符串不能出现显式的换行
			jsonText = jsonText.replaceAll("\n", "\\\\u000a");
		}
		return jsonText;
	}

	protected String JP(String propertyName, String value) {
		Assert.hasText(propertyName);
		propertyName = escapeJSONText(propertyName);
		if (StringUtils.hasText(value)) {
			value = escapeJSONText(value);
		} else {
			value = "";
		}
		return new StringBuffer("\"").append(propertyName).append("\":\"").append(value).append("\"").toString();
	}

	public String toJSON(Map<DataProperty, String> values) {
		StringBuilder jsonBuilder = new StringBuilder("{");
		boolean appended = false;
		for (Map.Entry<DataProperty, String> ve : values.entrySet()) {
			if (appended)
				jsonBuilder.append(",");
			jsonBuilder.append(JP(ve.getKey().getPropertyName(), ve.getValue()));
			appended = true;
		}

		jsonBuilder.append("}");
		return jsonBuilder.toString();
	}

	protected String relationMessageToJSON(MessageDataItem dataItem) {
		StringBuilder jsonBuilder = new StringBuilder();
		MessageEntity parentsMessages[] = dataItem.getParents();
		if (parentsMessages != null && parentsMessages.length > 0) {
			jsonBuilder.append(",\"p\":[");
			boolean appended = false;
			for (MessageEntity ppm : parentsMessages) {
				if (ppm.getDatas().length == 0)
					continue;
				if (appended)
					jsonBuilder.append(",");
				jsonBuilder.append(parentMessageToJSON(ppm));
				appended = true;
			}
			jsonBuilder.append("]");
		}
		MessageEntity childsMessages[] = dataItem.getChilds();
		if (childsMessages != null && childsMessages.length > 0) {
			jsonBuilder.append(",\"l\":[");
			boolean appended = false;
			for (MessageEntity pcm : childsMessages) {
				if (pcm.getDatas().length == 0)
					continue;
				if (appended)
					jsonBuilder.append(",");
				jsonBuilder.append(toJSON(pcm));
				appended = true;
			}
			jsonBuilder.append("]");
		}
		return jsonBuilder.toString();
	}

	protected String parentMessageToJSON(MessageEntity parentMsgEntity) {
		StringBuilder jsonBuilder = new StringBuilder("{");
		jsonBuilder.append(JP("c", parentMsgEntity.getHeader().getMessageCode()));
		MessageDataItem dataItem = parentMsgEntity.getDatas()[0];
		if (parentMsgEntity.getOwner().getHeader().getDefaultAction() != parentMsgEntity.getHeader().getDefaultAction()) {
			jsonBuilder.append(",").append(
					JP("t", new Integer(parentMsgEntity.getHeader().getDefaultAction().getCode()).toString()));
		}
		jsonBuilder.append(",\"v\":");
		jsonBuilder.append(toJSON(dataItem.getValues()));
		jsonBuilder.append(relationMessageToJSON(dataItem));
		jsonBuilder.append("}");
		return jsonBuilder.toString();
	}

	public String toJSON(MessageDataItem msgDataItem) {
		StringBuilder jsonBuilder = new StringBuilder("{");
		boolean appended = false;
		if (msgDataItem.getOwner().getHeader().getDefaultAction() != msgDataItem.getAction()) {
			jsonBuilder.append(JP("t", new Integer(msgDataItem.getAction().getCode()).toString()));
			appended = true;
		}
		if (msgDataItem.getValues().size() > 0) {
			if (appended)
				jsonBuilder.append(",");
			jsonBuilder.append("\"v\":");
			jsonBuilder.append(toJSON(msgDataItem.getValues()));
			jsonBuilder.append(relationMessageToJSON(msgDataItem));
		}
		jsonBuilder.append("}");
		return jsonBuilder.toString();
	}

	public String toJSON(MessageEntity msgEntity) {
		Assert.notNull(msgEntity);
		StringBuilder jsonBuilder = new StringBuilder("{");
		jsonBuilder.append(JP("c", msgEntity.getHeader().getMessageCode()));

		if (msgEntity.isTop()) {
			if (StringUtils.hasText(msgEntity.getHeader().getFrom())) {
				jsonBuilder.append(",").append(JP("f", msgEntity.getHeader().getFrom()));
			}
			if (StringUtils.hasText(msgEntity.getHeader().getMessageId())) {
				jsonBuilder.append(",").append(JP("k", msgEntity.getHeader().getMessageId()));
			}
			jsonBuilder.append(",").append(
					JP("t", new Integer(msgEntity.getHeader().getDefaultAction().getCode()).toString()));

			if (msgEntity.getHeader().getCreateTime() != null) {
				jsonBuilder.append(",").append(
						JP("m", getMessageDateFormat().format(msgEntity.getHeader().getCreateTime())));
			}
		} else if (msgEntity.getOwner().getHeader().getDefaultAction() != msgEntity.getHeader().getDefaultAction()) {
			jsonBuilder.append(",").append(
					JP("t", new Integer(msgEntity.getHeader().getDefaultAction().getCode()).toString()));
		}
		MessageDataItem dataItems[] = msgEntity.getDatas();
		if (dataItems != null && dataItems.length > 0) {
			jsonBuilder.append(",\"s\":[");
			boolean appended = false;
			for (MessageDataItem dataItem : dataItems) {
				if (dataItem.getValues().size() == 0)
					continue;
				if (appended)
					jsonBuilder.append(",");
				jsonBuilder.append(toJSON(dataItem));
				appended = true;
			}
			jsonBuilder.append("]");
		}
		jsonBuilder.append("}");
		return jsonBuilder.toString();
	}

	public MessageEntity newMessage(MessageEntity owner, String messageCode, DataAction defeaultAction,
			List<Map<DataProperty, String>> rows) {
		return newMessage(messageCode, defeaultAction, getMessageNamespace(), rows);
	}

	public MessageEntity newMessage(MessageEntity owner, String messageCode, DataAction defeaultAction,
			List<Map<DataProperty, String>> rows, MessageConcatenationResolver resolver) {
		return newMessage(owner, messageCode, defeaultAction, getMessageNamespace(), rows, resolver);
	}

	// 消息实体功能实现
	public MessageEntity newMessage(MessageEntity owner, String messageId, String messageCode,
			DataAction defeaultAction, String from, List<Map<DataProperty, String>> rows,
			MessageConcatenationResolver resolver) {
		Assert.hasText(messageCode);
		Assert.notEmpty(rows);
		resolver = resolver != null ? resolver : NullResolver.INSTANCE;
		if (!StringUtils.hasText(messageId))
			messageId = new StringBuilder(messageCode).append(CalendarUtils.idDateTimeFormat.format(new Date()))
					.toString();

		BaseMessageHeader msgHeader = new BaseMessageHeader();
		msgHeader.setMessageId(messageId);
		msgHeader.setMessageCode(messageCode);
		msgHeader.setFrom(from);
		msgHeader.setDefaultAction(defeaultAction);
		msgHeader.setCreateTime(new Date());
		BaseMessageEntity msg = new BaseMessageEntity();
		msg.setOwner(owner);
		msg.setHeader(msgHeader);
		for (Map<DataProperty, String> row : rows) {
			BaseMessageDataItem rowItem = new BaseMessageDataItem(msg);
			rowItem.setValues(row);
			try {
				MessageConcatenation mscc = resolver.resolveConcatenation(rowItem);
				if (mscc != null) {
					if (mscc.hasParents()) {
						rowItem.addParents(mscc.getParents());
					}
					if (mscc.hasChilds()) {
						rowItem.addChilds(mscc.getParents());
					}
				}
				msg.addData(rowItem);
			} catch (Throwable e) {
				throw new IllegalArgumentException(e.getMessage(), e);
			}
		}
		return msg;
	}

	public MessageEntity newMessage(MessageEntity owner, String messageCode, DataAction defeaultAction, String from,
			List<Map<DataProperty, String>> rows) {
		return newMessage(owner,
				new StringBuilder(messageCode).append(CalendarUtils.idDateTimeFormat.format(new Date())).toString(),
				messageCode, defeaultAction, from, rows, null);
	}

	public MessageEntity newMessage(String messageCode, DataAction defeaultAction, Map<DataProperty, String> row) {
		return newMessage(null, messageCode, defeaultAction, getMessageNamespace(), row);
	}

	public MessageEntity newMessage(MessageEntity owner, String messageCode, DataAction defeaultAction, String from,
			List<Map<DataProperty, String>> rows, MessageConcatenationResolver resolver) {
		Assert.hasText(messageCode);
		return newMessage(owner,
				new StringBuilder(messageCode).append(CalendarUtils.idDateTimeFormat.format(new Date())).toString(),
				messageCode, defeaultAction, from, rows, resolver);
	}

	public MessageEntity newMessage(String messageId, String messageCode, DataAction defeaultAction, String from,
			Map<DataProperty, String> row, MessageConcatenationResolver resolver) throws MessageException {
		Assert.notNull(row);
		List<Map<DataProperty, String>> rows = new ArrayList<Map<DataProperty, String>>(1);
		rows.add(row);
		return newMessage(null, messageId, messageCode, defeaultAction, from, rows, resolver);
	}

	public MessageEntity newMessage(String messageId, String messageCode, DataAction defeaultAction, String from,
			List<Map<DataProperty, String>> rows) {
		return newMessage(null, messageId, messageCode, defeaultAction, from, rows, null);
	}

	public MessageEntity newMessage(String messageCode, DataAction defeaultAction, String from,
			List<Map<DataProperty, String>> rows) {
		Assert.hasText(messageCode, "必须指定消息代码");
		return newMessage(new StringBuilder(messageCode).append(CalendarUtils.idDateTimeFormat.format(new Date()))
				.toString(), messageCode, defeaultAction, from, rows);
	}

	public MessageEntity newMessage(String messageId, String messageCode, DataAction defeaultAction, String from,
			Map<DataProperty, String> row) {
		Assert.notNull(row);
		List<Map<DataProperty, String>> rows = new ArrayList<Map<DataProperty, String>>(1);
		rows.add(row);
		return newMessage(messageId, messageCode, defeaultAction, from, rows);
	}

	public MessageEntity newMessage(Object object, DataAction defaultAction) throws MessageException {
		return MessageEntityUtils.convertPojoToMessageEntity(object, defaultAction, getMessageNamespace());
	}

	public MessageEntity newMessage(Object object, String messageIdOrVersion, DataAction defaultAction)
			throws MessageException {
		return MessageEntityUtils.convertPojoToMessageEntity(object, messageIdOrVersion, defaultAction,
				getMessageNamespace());
	}

	public MessageEntity newMessage(Object object, DataAction defaultAction, MessageEntityBuildCallback buildCallback)
			throws MessageException {
		return MessageEntityUtils.convertPojoToMessageEntity(object, defaultAction, getMessageNamespace(),
				buildCallback);
	}

	public MessageEntity newMessage(Object object, String messageIdOrVersion, DataAction defaultAction,
			MessageEntityBuildCallback buildCallback) throws MessageException {
		return MessageEntityUtils.convertPojoToMessageEntity(object, messageIdOrVersion, defaultAction,
				getMessageNamespace(), buildCallback);
	}

	protected static class MessageEntityResolver implements EntityResolver {

		private final InputStream xsdStream;

		public MessageEntityResolver(InputStream xsdStream) {
			this.xsdStream = xsdStream;
		}

		public InputSource resolveEntity(String s, String s1) throws SAXException, IOException {
			return new InputSource(xsdStream);
		}
	}

	private static class NullResolver implements MessageConcatenationResolver {

		public static final MessageConcatenationResolver INSTANCE = new NullResolver();

		public MessageConcatenation resolveConcatenation(MessageDataItem dataItem) throws MessageException {
			return null;
		}

	}

}
